* fileio.c (Fcopy_file): Adjust mode if fchown fails. (Bug#9002)
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 18 Jul 2011 17:21:18 +0000 (10:21 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 18 Jul 2011 17:21:18 +0000 (10:21 -0700)
If fchown fails to set both uid and gid, try to set just gid,
as that is sometimes allowed.  Adjust the file's mode to eliminate
setuid or setgid bits that are inappropriate if fchown fails.

src/ChangeLog
src/fileio.c

index 7809f221c3c8fb5cc0256a1ee89e7c2bbe781750..67dde81eb46c26dfd22f23dffad4c0e66ff3e2d6 100644 (file)
@@ -1,3 +1,10 @@
+2011-07-18  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * fileio.c (Fcopy_file): Adjust mode if fchown fails.  (Bug#9002)
+       If fchown fails to set both uid and gid, try to set just gid,
+       as that is sometimes allowed.  Adjust the file's mode to eliminate
+       setuid or setgid bits that are inappropriate if fchown fails.
+
 2011-07-18  Stefan Monnier  <monnier@iro.umontreal.ca>
 
        * xdisp.c (next_element_from_string, next_element_from_buffer): Use EQ
index a52e834c2b270758b6b59afe661da24c5b04c73a..fb2c081ae5c4af065e6f4a34160c47c22e4916cf 100644 (file)
@@ -38,8 +38,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <selinux/context.h>
 #endif
 
-#include <ignore-value.h>
-
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
@@ -1961,9 +1959,21 @@ on the system, we copy the SELinux context of FILE to NEWNAME.  */)
      owner and group.  */
   if (input_file_statable_p)
     {
+      int mode_mask = 07777;
       if (!NILP (preserve_uid_gid))
-       ignore_value (fchown (ofd, st.st_uid, st.st_gid));
-      if (fchmod (ofd, st.st_mode & 07777) != 0)
+       {
+         /* Attempt to change owner and group.  If that doesn't work
+            attempt to change just the group, as that is sometimes allowed.
+            Adjust the mode mask to eliminate setuid or setgid bits
+            that are inappropriate if the owner and group are wrong.  */
+         if (fchown (ofd, st.st_uid, st.st_gid) != 0)
+           {
+             mode_mask &= ~06000;
+             if (fchown (ofd, -1, st.st_gid) == 0)
+               mode_mask |= 02000;
+           }
+       }
+      if (fchmod (ofd, st.st_mode & mode_mask) != 0)
        report_file_error ("Doing chmod", Fcons (newname, Qnil));
     }
 #endif /* not MSDOS */